作業ログ | 全てのKeyboardEventとCompositionEventを握りつぶす
2022-04-25
13:16:02
捕捉した全てのeventをEvent.preventDefault()&Event.stopPropagation()して握りつぶす実装を作ってみた https://github.com/takker99/ScrapVim/commit/940356656957a708e10215772ff479f3ceb51318
これで一旦試してみる
code:sh
deno check https://scrapbox.io/api/code/takker/takker99%2FScrapVim/test.ts
code:test.ts
import { useStatusBar, textInput, takeCursor, insertText } from "../scrapbox-userscript-std/dom.ts";
import { commandWatcher } from "https://raw.githubusercontent.com/takker99/ScrapVim/fix-event/commandWatcher.ts";
let mode: "normal" | "input" = "normal";
const execNormal = (command: string) => {
const cursor = takeCursor();
switch (command) {
case "h":
cursor.goByAction("go-left");
return;
case "j":
cursor.goByAction("go-down");
return;
case "k":
cursor.goByAction("go-up");
return;
case "l":
cursor.goByAction("go-right");
return;
case "i":
mode = "input";
return;
}
}
const execInput = (command: string) => {
const cursor = takeCursor();
switch (command) {
case "<C-[>":
case "<Esc>":
mode = "normal";
return;
default:
insertText(command);
return;
}
}
let message = [] as string[];
const log = useStatusBar();
mode = "normal";
const { render, dispose } = useStatusBar();
render({ type: "text", text: mode });
for await (const command of commandWatcher(textInput()!)) {
message.push(command);
if (message.length > 10) message.shift();
switch (mode as "normal" | "input") {
case "normal":
execNormal(command);
break;
case "input":
execInput(command);
break;
}
log.render({ type: "text", text: message.join("") });
render({ type: "text", text: mode });
}
log.dispose();
dispose();
14:00:54 #text-inputのevent listenerだと、完全には握りつぶせない
矢印キーとcomposition eventを握りつぶせれれれなかった
#editorならどうだろう?
14:03:20 握りつぶせなかった……
14:10:35 そもそも握りつぶせるのか?
14:13:45 あり?これで矢印キーなら握りつぶせるっぽい……
code:js
document.getElementById("editor").addEventListener("keydown", e => {
if (!e.isTrusted) return;
e.preventDefault();
e.stopPropagation();
console.log(e);
})
あ、keydownイベントをdocumentでlistenしようとしていたからだ
これも#editorや#text-inputでlistenすれば握りつぶせる
14:16:15 CompositionEventも試す
#editorだと止まらない
code:js
document.getElementById("editor").addEventListener("compositionend", e => {
if (!e.isTrusted) return;
e.preventDefault();
e.stopPropagation();
console.log(e);
});
#text-inputでも無理
code:js
document.getElementById("text-input").addEventListener("compositionend", e => {
if (!e.isTrusted) return;
e.stopPropagation();
console.log(e);
});
Event.cancelableがfalseだから、Event.preventDefault()は無効
Event.stopImmediatePropagation()も試してみたがだめだった
capture phaseを使ったら成功した!
ただし、#text-inputにcompositionendが送られないせいで、convert-modeが中断されず、入力がおかしなことになる
code:js
document.addEventListener("compositionend", e => {
if (!e.isTrusted) return;
if (e.target.id !== "text-input") return;
e.stopPropagation();
console.log(e);
}, { capture: true });
const event = new CompositionEvent("compositionend", { data: "" });document.getElementById("text-input").dispatchEvent(event);で終了イベントを送ると、直前の文字列が流し込まれてしまう
どうやらdataを#text-input側で保持していて、compositionendの値は使われないようだ
HTMLTextareaElement.valueを消してから偽装eventを発行したら成功した!
mobileは未確認。ソースを見てみると、HTMLTextareaElement.valueの値を入力しているようだから、同様に成功すると思う
code:js
document.addEventListener("compositionend", e => {
if (!e.isTrusted) return;
if (e.target.id !== "text-input") return;
e.stopPropagation();
console.log(e);
document.getElementById("text-input").value = "";
const event = new CompositionEvent("compositionend", { data: "" });
document.getElementById("text-input").dispatchEvent(event);
}, { capture: true });
#2022-04-25 15:08:24